xenfb: Dynamic modes support.
authorKeir Fraser <keir.fraser@citrix.com>
Wed, 26 Mar 2008 09:09:16 +0000 (09:09 +0000)
committerKeir Fraser <keir.fraser@citrix.com>
Wed, 26 Mar 2008 09:09:16 +0000 (09:09 +0000)
Attached patch adds dynamic frame buffer size support to the xenfb PV
backend QEMU xenfb.  Backend sets feature-resize and handles the
resize frame buffer event.

Corresponding frontend LINUX patch is required for functionality but
this patch is not dependent on it, preserving backwards
compatibility.

Signed-off-by: Pat Campbell <plc@novell.com>
tools/ioemu/hw/xenfb.c
tools/python/xen/xend/server/vfbif.py
tools/python/xen/xm/create.py
xen/include/public/io/fbif.h

index affbcaaa0df83e38372909300e42129f214ecb20..0ea088580ae468ec8b122fa2a8e92bf38238a0ec 100644 (file)
@@ -516,6 +516,16 @@ static void xenfb_on_fb_event(struct xenfb *xenfb)
                        }
                        xenfb_guest_copy(xenfb, x, y, w, h);
                        break;
+               case XENFB_TYPE_RESIZE:
+                       xenfb->width  = event->resize.width;
+                       xenfb->height = event->resize.height;
+                       xenfb->row_stride = event->resize.stride;
+                       dpy_colourdepth(xenfb->ds, xenfb->depth);
+                       dpy_resize(xenfb->ds, xenfb->width, xenfb->height, xenfb->row_stride);
+                       if (xenfb->ds->shared_buf)
+                               dpy_setdata(xenfb->ds, xenfb->pixels);
+                       xenfb_invalidate(xenfb);
+                       break;
                }
        }
        xen_mb();               /* ensure we're done with ring contents */
@@ -680,6 +690,7 @@ static void xenfb_dispatch_store(void *opaque)
 static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) {
        struct xenfb_page *fb_page;
        int val;
+       int videoram;
 
         if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "feature-update",
                             "%d", &val) < 0)
@@ -702,11 +713,31 @@ static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) {
         /* TODO check for consistency with the above */
         xenfb->fb_len = fb_page->mem_length;
         xenfb->row_stride = fb_page->line_length;
+
+        /* Protect against hostile frontend, limit fb_len to max allowed */
+        if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.nodename, "videoram", "%d",
+                            &videoram) < 0)
+                videoram = 0;
+        videoram = videoram * 1024 * 1024;
+        if (videoram && xenfb->fb_len > videoram) {
+                fprintf(stderr, "Framebuffer requested length of %zd exceeded allowed %d\n",
+                        xenfb->fb_len, videoram);
+                xenfb->fb_len = videoram;
+                if (xenfb->row_stride * xenfb->height > xenfb->fb_len)
+                        xenfb->height = xenfb->fb_len / xenfb->row_stride;
+        }
         fprintf(stderr, "Framebuffer depth %d width %d height %d line %d\n",
                 fb_page->depth, fb_page->width, fb_page->height, fb_page->line_length);
         if (xenfb_map_fb(xenfb, xenfb->fb.otherend_id) < 0)
                return -1;
 
+        /* Indicate we have the frame buffer resize feature */
+        xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "feature-resize", "1");
+
+        /* Tell kbd pointer the screen geometry */
+        xenfb_xs_printf(xenfb->xsh, xenfb->kbd.nodename, "width", "%d", xenfb->width);
+        xenfb_xs_printf(xenfb->xsh, xenfb->kbd.nodename, "height", "%d", xenfb->height);
+
         if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
                 return -1;
         if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
index a79f50f0194982b5a0faabb9d2dcd3df9a80e6a5..6f049d3c130bf6049cd7e112760ce56ef6ad1d05 100644 (file)
@@ -6,7 +6,7 @@ import xen.xend
 import os
 
 CONFIG_ENTRIES = ['type', 'vncdisplay', 'vnclisten', 'vncpasswd', 'vncunused',
-                  'display', 'xauthority', 'keymap',
+                  'videoram', 'display', 'xauthority', 'keymap',
                   'uuid', 'location', 'protocol', 'opengl']
 
 class VfbifController(DevController):
index a4e756825f50710f3e42d2fae02d646c8e269346..66c19afb5c62258f094989489b6bf64ec08af1d9 100644 (file)
@@ -500,6 +500,11 @@ gopts.var('vncunused', val='',
           use="""Try to find an unused port for the VNC server.
           Only valid when vnc=1.""")
 
+gopts.var('videoram', val='',
+          fn=set_value, default=None,
+          use="""Maximum amount of videoram PV guest can allocate
+          for frame buffer.""")
+
 gopts.var('sdl', val='',
           fn=set_value, default=None,
           use="""Should the device model use SDL?""")
@@ -645,7 +650,8 @@ def configure_vfbs(config_devs, vals):
             d['type'] = 'sdl'
         for (k,v) in d.iteritems():
             if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display',
-                          'xauthority', 'type', 'vncpasswd', 'opengl' ]:
+                          'videoram', 'xauthority', 'type', 'vncpasswd',
+                          'opengl' ]:
                 err("configuration option %s unknown to vfbs" % k)
             config.append([k,v])
         if not d.has_key("keymap"):
index 261d756113171293f82ae9102ae555051a5af714..d27cfa091a93953af71f273856819f0c34923731 100644 (file)
@@ -50,12 +50,28 @@ struct xenfb_update
     int32_t height; /* rect height */
 };
 
+/*
+ * Framebuffer resize notification event
+ * Capable backend sets feature-resize in xenstore.
+ */
+#define XENFB_TYPE_RESIZE 3
+
+struct xenfb_resize
+{
+    uint8_t type;    /* XENFB_TYPE_RESIZE */
+    int32_t width;   /* width in pixels */
+    int32_t height;  /* height in pixels */
+    int32_t stride;  /* stride in bytes */
+    int32_t depth;   /* depth in bits */
+};
+
 #define XENFB_OUT_EVENT_SIZE 40
 
 union xenfb_out_event
 {
     uint8_t type;
     struct xenfb_update update;
+    struct xenfb_resize resize;
     char pad[XENFB_OUT_EVENT_SIZE];
 };
 
@@ -109,15 +125,17 @@ struct xenfb_page
      * Each directory page holds PAGE_SIZE / sizeof(*pd)
      * framebuffer pages, and can thus map up to PAGE_SIZE *
      * PAGE_SIZE / sizeof(*pd) bytes.  With PAGE_SIZE == 4096 and
-     * sizeof(unsigned long) == 4, that's 4 Megs.  Two directory
-     * pages should be enough for a while.
+     * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 Megs
+     * 64 bit.  256 directories give enough room for a 512 Meg
+     * framebuffer with a max resolution of 12,800x10,240.  Should
+     * be enough for a while with room leftover for expansion.
      */
-    unsigned long pd[2];
+    unsigned long pd[256];
 };
 
 /*
- * Wart: xenkbd needs to know resolution.  Put it here until a better
- * solution is found, but don't leak it to the backend.
+ * Wart: xenkbd needs to know default resolution.  Put it here until a
+ * better solution is found, but don't leak it to the backend.
  */
 #ifdef __KERNEL__
 #define XENFB_WIDTH 800